/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.web.core.param;


import java.lang.annotation.Annotation;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import com.jfast.framework.kit.StrKit;
import com.jfast.framework.orm.TypeConvert;
import com.jfast.framework.web.annotation.PathVariable;
import com.jfast.framework.web.annotation.RequestBody;
import com.jfast.framework.web.annotation.RequestParam;
import com.jfast.framework.web.core.RequestMethodMapping;

public class AnnotationParam extends RequestMappingMethodParam {

	private Annotation annotation;
	private Class<?> clazz;
	private RequestMethodMapping requestMethodMapping;
	private String parameterName;
	private final RequestBodyProcessor requestBodyProcessor;
	private RequestMappingMethodParam delegate;
	
	public AnnotationParam(RequestMethodMapping requestMethodMapping, HttpServletRequest request,
						  String parameterName, Annotation annotation, Class<?> clazz) {
		super(request);
		this.requestMethodMapping = requestMethodMapping;
		this.parameterName = parameterName;
		this.annotation = annotation;
		this.clazz = clazz;
		this.requestBodyProcessor = new RequestBodyProcessor(request);
	}

	@Override
	public Object getParam() {
		Object value = null;
		//优先处理PathVariable参数
        if (annotation instanceof PathVariable) {
			setJsonParams(false);
			PathVariable pathVariable = (PathVariable) annotation;
			Map pathVariableMap = requestMethodMapping.getPathVariableMap();
			return TypeConvert.convert(clazz, StrKit.isEmpty(pathVariable.value()) ? (String)pathVariableMap.get(parameterName)
					: (String)pathVariableMap.get(pathVariable.value()));
		} else if (annotation instanceof RequestParam) {
			setJsonParams(false);
			RequestParam param = (RequestParam) annotation;
			String name = param.value();
			if (StrKit.isEmpty(name)) {
				name = parameterName;
			}
			Object defaultValue = null;
		    value = TypeConvert.convert(clazz, request.getParameter(name));
			if (StrKit.isNotEmpty(param.defaultValue())) {
			    defaultValue =  TypeConvert.convert(clazz, param.defaultValue());
			}
			return StrKit.isEmpty(value) ? defaultValue : value;
		} else if (annotation instanceof RequestBody) {
			setJsonParams(true);
			delegate = requestBodyProcessor.getMethodParam(clazz);
			return delegate.getParam();
		} else {
        	throw new RuntimeException();
		}
	}

	@Override
	Object doGetBean(Map<String, String[]> params) {
		return null;
	}

	@Override
	Object doGetBeanByJson(String requestBody) {
		return null;
	}

	/**
	 * RequestBody 参数注入处理器
	 * @since 1.1
	 */
	static class RequestBodyProcessor {

		private final Map<Object, RequestMappingMethodParam> requestBody = new HashMap();

		RequestBodyProcessor(HttpServletRequest request) {
			registerParameterType(Map.class, new MapParam<String, Object>(request));
			registerParameterType(Object.class, new BeanParam(request, null));
		}

		public void setBeanClass(Class<?> beanClass) {
			BeanParam beanParam = (BeanParam)requestBody.get(Object.class);
			beanParam.setBeanClass(beanClass);
		}

		private void registerParameterType(Class<?> clazz, RequestMappingMethodParam methodParam) {
			requestBody.put(clazz, methodParam);
		}

		public RequestMappingMethodParam getMethodParam(Class<?> clazz) {
			if (clazz != Collection.class || clazz != Map.class) {
				setBeanClass(clazz);
				return requestBody.get(Object.class);
			}
			return requestBody.get(clazz);
		}
	}
}
